"""
@File    :   boost_task.py
@Time    :   2024/03/02 11:56:51
@Author  :   Qrj
@Email   :   923207736@qq.com
@description   :   Token的funboost异步任务
"""


from funboost import BoosterParams, BrokerEnum, ConcurrentModeEnum, boost
from redis.asyncio import Redis
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker

from src.config import get_app_settings
from src.enums.redis_db import RedisDbNumEnum

from .typings import RefreshTokenAndUserIdMappingsT

# 获取应用配置
settings = get_app_settings()

# 创建sql连接池
# 创建异步引擎对象
async_engine = create_async_engine(
    settings.master_async_orm_url,
    echo=settings.orm_echo,
    future=settings.orm_future,
    pool_size=settings.orm_process_pool_size,
    pool_pre_ping=settings.orm_pool_pre_ping,
)

# 创建异步会话管理对象(连接池对象, 每次调用就会取出一个连接)
masterSessionLocal = sessionmaker(
    async_engine,
    class_=AsyncSession,
    autocommit=settings.orm_auto_commit,
    autoflush=settings.orm_auto_flush,
    expire_on_commit=settings.orm_expire_on_commit,
)

# 创建Redis连接池
redis_pool = Redis(
    host=settings.redis_host,
    password=settings.redis_password,
    port=settings.redis_port,
    db=RedisDbNumEnum.token_db.value,
    decode_responses=True,
)


@boost(
    BoosterParams(
        queue_name="queue_create_double_token_clean_user_logged_tokens_zset",
        broker_kind=BrokerEnum.REDIS_STREAM,
        concurrent_mode=ConcurrentModeEnum.ASYNC,
        qps=100,
        concurrent_num=300,
        log_level=30,
        create_logger_file=False,
    )
)
async def create_double_token_clean_user_logged_tokens_zset_handler(
    user_id: int, user_number_of_simultaneous_logins: int
):
    """登录(创建双Tokne)时清理用户的已登录双token的zset

    Args:
        user_id (int): 用户ID
        user_number_of_simultaneous_logins (int): 该用户的最大同时登录数
    """
    # 运行时导入, 防止循环导入
    from .service import TokenService

    # 从sql连接池中取出连接
    db_session = masterSessionLocal()
    try:
        # 清理用户的已登录双token的zset
        await TokenService.create_double_token_clean_user_logged_tokens_zset(
            db_session, redis_pool, user_id, user_number_of_simultaneous_logins
        )
    finally:
        # 关闭sql连接
        await db_session.close()


@boost(
    BoosterParams(
        queue_name="queue_refresh_access_token_user_logged_token_zset",
        broker_kind=BrokerEnum.REDIS_STREAM,
        concurrent_mode=ConcurrentModeEnum.ASYNC,
        qps=100,
        concurrent_num=300,
        log_level=30,
        create_logger_file=False,
    )
)
async def refresh_access_token_clean_user_logged_token_zset_handler(
    user_id: int,
    new_access_token: str,
    refresh_token: str,
):
    """使用刷新令牌刷新访问令牌时清理用户的已登录双token的zset

    Args:
        user_id (int): 用户ID
        new_access_token (str): 使用refresh_token刷新出的新的access_token
        refresh_token (str): 刷新令牌
    """
    # 运行时导入, 防止循环导入
    from .service import TokenService

    # 从sql连接池中取出连接
    db_session = masterSessionLocal()
    try:
        # 清理用户的已登录双token的zset
        await TokenService.refresh_access_token_clean_user_logged_token_zset(
            db_session, redis_pool, user_id, new_access_token, refresh_token
        )
    finally:
        # 关闭sql连接
        await db_session.close()


@boost(
    BoosterParams(
        queue_name="queue_delete_double_tokens_clean_user_logged_token_zset",
        broker_kind=BrokerEnum.REDIS_STREAM,
        concurrent_mode=ConcurrentModeEnum.ASYNC,
        qps=100,
        concurrent_num=300,
        log_level=30,
        create_logger_file=False,
    )
)
async def delete_double_tokens_clean_user_logged_token_zset_handler(
    refresh_token_and_user_id_mappings: RefreshTokenAndUserIdMappingsT,
):
    """删除双Token时清理用户的已登录双token的zset

    Args:
        refresh_token_and_user_id_mappings (RefreshTokenAndUserIdMappingsT): 刷新token及其对应的用户id的映射列表
    """
    from .service import TokenService

    # 清理用户的已登录双token的zset
    await TokenService.delete_double_tokens_clean_user_logged_token_zset(
        redis_pool, refresh_token_and_user_id_mappings
    )


@boost(
    BoosterParams(
        queue_name="queue_delete_expired_double_tokens_timed_task",
        broker_kind=BrokerEnum.REDIS_STREAM,
        concurrent_mode=ConcurrentModeEnum.ASYNC,
        log_level=30,
        create_logger_file=False,
    )
)
async def delete_expired_double_tokens_timed_handler():
    """定时删除过期的双Token"""
    # 运行时导入, 防止循环导入
    from .service import TokenService

    # 从sql连接池中取出连接
    db_session = masterSessionLocal()
    try:
        # 删除过期的双Token
        await TokenService.delete_expired_double_tokens(db_session, redis_pool)
    finally:
        # 关闭sql连接
        await db_session.close()
